package cshi.common;


import java.io.File;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.TimeUnit;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.codahale.metrics.*;

//differences between meter and timer
//http://stackoverflow.com/questions/30987757/dropwizard-metrics-meters-vs-timers

//authoriative docs
//http://metrics.dropwizard.io/3.1.0/manual/core

public class MetricsTest {
	public static Logger logger = LoggerFactory.getLogger(MetricsTest.class);
	
	static final MetricRegistry metrics = new MetricRegistry();
	private static Queue<String> queue = new LinkedBlockingDeque<String>();
	
	private static ConsoleReporter reporter2 = ConsoleReporter.forRegistry(metrics).build();
	
	static ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
	          .convertRatesTo(TimeUnit.SECONDS)
	          .convertDurationsTo(TimeUnit.MILLISECONDS)
	          .build();
	
	static CsvReporter csv = CsvReporter.forRegistry(metrics)
            .formatFor(Locale.US)
            .convertRatesTo(TimeUnit.SECONDS)
            .convertDurationsTo(TimeUnit.MILLISECONDS)
            .build(new File("./bin/"));
	
	static final Slf4jReporter slf4jReporter = Slf4jReporter.forRegistry(metrics)
            .outputTo(LoggerFactory.getLogger("cshi.common.MetricsTest"))
            .convertRatesTo(TimeUnit.SECONDS)
            .convertDurationsTo(TimeUnit.MILLISECONDS)
            .build();

	 /**
     * 实例化一个counter,同样可以通过如下方式进行实例化再注册进去
     * pendingJobs = new Counter();
     * metrics.register(MetricRegistry.name(TestCounter.class, "pending-jobs"), pendingJobs);
     */
	
	public static void handleRequest(Meter meter){
		meter.mark();
	}
	
	//Meters用来度量某个时间段的平均处理次数（request per second），每1、5、15分钟的TPS。
	//比如一个service的请求数，通过metrics.meter()实例化一个Meter之后，然后通过meter.mark()
	//方法就能将本次请求记录下来。统计结果有总的请求数，平均每秒的请求数，以及最近的1、5、15分钟的平均TPS。
	public static void meterTest() throws InterruptedException{
		csv.start(1, TimeUnit.SECONDS);
		
		Meter requests = metrics.meter("requests");
		reporter.start(3, TimeUnit.SECONDS);
        while(true){
            handleRequest(requests);
            Thread.sleep(100);
        }
	}
	
	//Gauges是一个最简单的计量，一般用来统计瞬时状态的数据信息，比如系统中处于pending状态的job
	public static void gaugeTest() throws InterruptedException{
		//reporter2.start(3, TimeUnit.SECONDS);//每隔3s向控制台打印一次
	
		Gauge<Integer> gauge = new Gauge<Integer>() {
		    public Integer getValue() {
		        return queue.size();
		    }
		};
		
		 //注册到容器中
        metrics.register(MetricRegistry.name(MetricsTest.class, "gauge-job", "size"), gauge);

        //JmxReporter可用于VisualVM在MBeans插件中查看
        JmxReporter jmxReporter = JmxReporter.forRegistry(metrics).build();
        jmxReporter.start();

        //模拟数据
        for (int i=0; i<2000; i++){
            queue.add("a");
            Thread.sleep(200);
        }

	}
	
	public static void add(Counter counterObj,String str) {
		counterObj.inc();
        queue.offer(str);
    }

    public String take(Counter counterObj) {
    	counterObj.dec();
        return queue.poll();
    }
    
    //Counter是Gauge的一个特例，维护一个计数器，可以通过inc()和dec()方法对计数器做修改
	public static void counterTest() throws InterruptedException{	
		slf4jReporter.start(1, TimeUnit.MINUTES);
		
		//只要创建，统计就会开始
		Counter counterObj = metrics.counter(MetricRegistry.name(MetricsTest.class, "counter-jobs"));
        while(true){
            add(counterObj,"1");
          
            Thread.sleep(500);
        }
	}
	
	//Histograms主要使用来统计数据的分布情况，最大值、最小值、平均值、中位数，
	//百分比（75%、90%、95%、98%、99%和99.9%）。例如，需要统计某个页面的请求响应时间分布情况，可以使用该种类型的Metrics进行统计
	public static void histTest() throws InterruptedException{
		Histogram randomNums = metrics.histogram(MetricRegistry.name(MetricsTest.class, "hist-test"));
		reporter2.start(3, TimeUnit.SECONDS);
        Random rand = new Random();
        while(true){
        	randomNums.update((int) (rand.nextDouble()*100));
            Thread.sleep(100);
        }
	}
	
	//Timers主要是用来统计某一块代码段的执行时间以及其分布情况，具体是基于Histograms和Meters来实现的
	//输出的count表示某段时间有几次调用
	public static void timerTest(){
		reporter2.start(3, TimeUnit.SECONDS);
		
		Timer requests = metrics.timer(MetricRegistry.name(MetricsTest.class, "request"));
		
        Random random = new Random();
        while(true){
            Timer.Context context = requests.time();
            try {
                //some operator
                Thread.sleep(random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                context.stop();
            }
        }
	}
	
	public static void main(String[] args) throws Exception {
		//histTest();
		counterTest();
		//gaugeTest();
		//meterTest();
		//timerTest();
	}

}
